package importselectort;

import cn.zcy.ann.Myanno;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AspectJTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * 自定义导入器
 */
@Myanno
public class CustomeImportSelectort implements ImportSelector {
    //表达式（ASPECTJ表达式）
    private String expression;

    /**
     * 默认构造函数
     * 用于读取配置文件，给表达式赋值
     */
    public CustomeImportSelectort() {
        try {
            //获取properties对象
            Properties properties = PropertiesLoaderUtils.loadAllProperties("customerimport.properties");
            expression = properties.getProperty("custome.importselectort.expression");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 实现获取要导入类的字节码
     * 需求：导入的过滤规则采用TypeFilter采用aspectj表达式方式
     *
     * @param importingClassMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //1.定义扫描宝的名称
        String[] basePackages = null;
        //2.判断有@Import注解的类上有没有 @ComponentScan注解getName()：这是 Class 类中的一个方法，
        // 它返回类的完全限定名（fully qualified name）。即，它返回类的全名，包括包名。例如，对于 ComponentScan 类，getName()
        // 方法将返回 org.springframework.context.annotation.ComponentScan，这是 ComponentScan 类的完全限定名。
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            //3.取出@ComponentScan属性的值 basePackage 或value
            Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
            //4.获取属性的值basePackage
            basePackages = (String[]) attributes.get("basePackages");
        }
        //5.判断是否有次注解   是否指定了包扫描信息
        if (basePackages == null || basePackages.length == 0) {
            String basePackage = null;
            try {
                //6.取出@Import注释的类所在的包名称
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

            //7.把包名填充到basePackages
            basePackages = new String[]{basePackage};
        }
        //8.创建类路径扫描器 参数的含义：表明不使用默认过滤规则
        ClassPathScanningCandidateComponentProvider scan = new ClassPathScanningCandidateComponentProvider(false);
        //9.创建类型过滤器，（此处采用Acpectj表达式）
        TypeFilter typeFilter = new AspectJTypeFilter(expression, CustomeImportSelectort.class.getClassLoader());
        //10.吧类型过滤器添加到扫描器中
        scan.addIncludeFilter(typeFilter);
        //11.定义要扫描类的全限定类名集合
        Set<String> classes = new HashSet<>();
        //12.填充集合的内容
        for (String basePackage : basePackages) {
            scan.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
        }
        //返回
        return classes.toArray(new String[classes.size()]);
    }
}

